home *** CD-ROM | disk | FTP | other *** search
/ Aminet 24 / Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso / Aminet / comm / mail / Mutt089src.lha / Mutt-0.89i-AMIGA / src / rfc1524.c < prev    next >
C/C++ Source or Header  |  1998-01-28  |  17KB  |  677 lines

  1. /*
  2.  * Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
  3.  * 
  4.  *     This program is free software; you can redistribute it and/or modify
  5.  *     it under the terms of the GNU General Public License as published by
  6.  *     the Free Software Foundation; either version 2 of the License, or
  7.  *     (at your option) any later version.
  8.  * 
  9.  *     This program is distributed in the hope that it will be useful,
  10.  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *     GNU General Public License for more details.
  13.  * 
  14.  *     You should have received a copy of the GNU General Public License
  15.  *     along with this program; if not, write to the Free Software
  16.  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  */ 
  18.  
  19. /* 
  20.  * rfc1524 defines a format for the Multimedia Mail Configuration, which
  21.  * is the standard mailcap file format under Unix which specifies what 
  22.  * external programs should be used to view/compose/edit multimedia files
  23.  * based on content type.
  24.  *
  25.  * This file contains various functions for implementing a fair subset of 
  26.  * rfc1524.
  27.  */
  28.  
  29. #include "mutt.h"
  30. #include "rfc1524.h"
  31.  
  32. #include <ctype.h>
  33. #include <stdlib.h>
  34. #include <unistd.h>
  35. #include <sys/wait.h>
  36. #include <string.h>
  37.  
  38. /* The command semantics include the following:
  39.  * %s is the filename that contains the mail body data
  40.  * %t is the content type, like text/plain
  41.  * \% is %
  42.  * Unsupported rfc1524 parameters: these would probably require some doing
  43.  * by mutt, and can probably just be done by piping the message to metamail
  44.  * %{parameter} is replaced by the parameter value from the content-type field
  45.  * %n is the integer number of sub-parts in the multipart
  46.  * %F is "content-type filename" repeated for each sub-part
  47.  *
  48.  * In addition, this function returns a 0 if the command works on a file,
  49.  * and 1 if the command works on a pipe.
  50.  */
  51. int rfc1524_expand_command (BODY *a, char *filename, char *type, 
  52.     char *command, int clen)
  53. {
  54.   int x=0,y=0;
  55.   int needspipe = TRUE;
  56.   char buf[LONG_STRING];
  57.  
  58.   while (command[x] && x<clen && y<sizeof(buf)) {
  59.     if (command[x] == '\\') {
  60.       x++;
  61.       buf[y++] = command[x++];
  62.     }
  63.     else if (command[x] == '%') {
  64.       x++;
  65.       if (command[x] == '{') {
  66.     char param[STRING];
  67.     int z = 0;
  68.     char *ret = NULL;
  69.  
  70.     x++;
  71.     while (command[x] && command[x] != '}' && z<sizeof(param))
  72.       param[z++] = command[x++];
  73.     param[z] = '\0';
  74.     dprint(2,(debugfile,"Parameter: %s  Returns: %s\n",param,ret));
  75.     ret = mutt_get_parameter(param,a->parameter);
  76.     dprint(2,(debugfile,"Parameter: %s  Returns: %s\n",param,ret));
  77.     z = 0;
  78.     while (ret && ret[z] && y<sizeof(buf))
  79.       buf[y++] = ret[z++];
  80.       }
  81.       else if (command[x] == 's' && filename != NULL)
  82.       {
  83.     char *fn = filename;
  84.  
  85.     while (*fn && y < sizeof (buf))
  86.       buf[y++] = *fn++;
  87.     needspipe = FALSE;
  88.       }
  89.       else if (command[x] == 't')
  90.       {
  91.     while (*type && y < sizeof (buf))
  92.       buf[y++] = *type++;
  93.       }
  94.       x++;
  95.     }
  96.     else
  97.       buf[y++] = command[x++];
  98.   }
  99.   buf[y] = '\0';
  100.   strfcpy (command, buf, clen);
  101.  
  102.   return needspipe;
  103. }
  104.  
  105. int rfc1524_mailcap_parse (BODY *a,
  106.                char *filename,
  107.                char *type, 
  108.                rfc1524_entry *entry,
  109.                int opt)
  110. {
  111.   FILE *fp = NULL;
  112.   char buf[LONG_STRING];
  113.   char basetype[STRING];
  114.   char *ch;
  115.   int found = FALSE;
  116.   int match = TRUE;
  117.   int wrap = FALSE;
  118.   int copiousoutput = FALSE;
  119.   int composecommand = FALSE;
  120.   int editcommand = FALSE;
  121.   int printcommand = FALSE;
  122.   int x = 0, y = 0;
  123.   int btlen = 0;
  124.  
  125.   /* rfc1524 mailcap file is of the format:
  126.    * base/type; command; extradefs
  127.    * type can be * for matching all
  128.    * base with no /type is an implicit wild
  129.    * command contains a %s for the filename to pass, default to pipe on stdin
  130.    * extradefs are of the form:
  131.    *  def1="definition"; def2="define \;";
  132.    * line wraps with a \ at the end of the line
  133.    * # for comments
  134.    */
  135.   if ((fp = fopen (filename, "r")) != NULL)
  136.   {
  137.     /* copy base type into basetype */
  138.     x = 0;
  139.     while (type[x] && x < sizeof (basetype) && type[x] != '/')
  140.     {
  141.       basetype[x] = type[x];
  142.       x++;
  143.     }
  144.     basetype[x] = '\0';
  145.     dprint (2, (debugfile, "mailcap basetype: %s\n", basetype));
  146.     btlen = x;
  147.     while (!found && fgets (buf, sizeof (buf), fp))
  148.     {
  149.       /* Strip comments (ie, everything after #, but not \# */
  150.       if ((ch = strchr (buf, '#')))
  151.         if ((ch == buf) || (*(ch-1) != '\\'))
  152.       *ch = '\0';
  153.   
  154.       /* Strip trailing white space */
  155.       y = strlen (buf);
  156.       y = (y ? y - 1 : 0);
  157.       while (y && (buf[y] == ' ' || buf[y] == '\t' || buf[y] == '\n'))
  158.     buf[y--] = '\0';
  159.   
  160.       /* handle line wrap */
  161.       if (buf[y] == '\\')
  162.     wrap = TRUE;
  163.       else
  164.     wrap = FALSE;
  165.  
  166.       while (wrap && fgets (buf + strlen (buf) - 1, sizeof (buf) - strlen (buf),fp)) 
  167.       {
  168.     if ((ch = strchr (buf,'#')))
  169.     {
  170.       if (*(ch-1) != '\\')
  171.         *ch = '\0';
  172.     }
  173.     y = strlen (buf);
  174.     y = (y ? y - 1 : 0);
  175.     while (buf[y] == ' ' || buf[y] == '\t' || buf[y] == '\n') 
  176.       buf[y--] = '\0';
  177.     if (buf[y] == '\\')
  178.       wrap = TRUE; 
  179.     else
  180.       wrap = FALSE; 
  181.       }
  182.       dprint (2, (debugfile, "mailcap entry: %s\n", buf));
  183.  
  184.       if (!strncasecmp (buf, type, strlen (type)) && (buf[strlen (type)] == ';'))
  185.     found = TRUE;
  186.       else
  187.       {
  188.     /* Check * case */
  189.     if (strncmp (buf, basetype, btlen-1) == 0)
  190.     {
  191.       /* check * wildcard */ 
  192.       if (buf[btlen] && buf[btlen+1] && buf[btlen] == '/' && 
  193.           buf[btlen+1] == '*') 
  194.         found = TRUE;
  195.       /* check implicit wild */
  196.       else if (buf[btlen] && buf[btlen] == ';')
  197.         found = TRUE;
  198.     }
  199.       }
  200.  
  201.       /* Parse the found line for the information we need */
  202.       if (found)
  203.       {
  204.     char *tok;
  205.     int z = 0, i = 0;
  206.     char token[STRING];
  207.  
  208.     /* first field is content type, already checked, so skip */
  209.     while (z < sizeof (buf) && buf[z] && buf[z] != ';')
  210.       z++;
  211.     z++;
  212.  
  213.     /* next field is the command */
  214.     while (z < sizeof (buf) && i < sizeof (token) && buf[z] && 
  215.           !(buf[z] == ';' && buf[z-1] != '\\'))
  216.       token[i++] = buf[z++];
  217.     token[i] = '\0';
  218.     z++;
  219.     tok = mutt_skip_whitespace (token);
  220.     if (entry)
  221.       entry->command = safe_strdup (tok);
  222.  
  223.     /* parse the optional fields */
  224.     /* next field is the command */
  225.     i = 0; 
  226.     while (z < sizeof (buf) && i < sizeof (token) && buf[z] && 
  227.           !(buf[z] == ';' && buf[z-1] != '\\')) 
  228.       token[i++] = buf[z++];
  229.     token[i] = '\0';
  230.     z++;
  231.     while (token[0])
  232.     {
  233.       tok = mutt_skip_whitespace (token);
  234.       dprint (2, (debugfile, "token: %s\n", tok));
  235.       if (!strcasecmp (tok, "needsterminal"))
  236.       {
  237.         if (entry)
  238.           entry->needsterminal = TRUE;
  239.       }
  240.       else if (!strcasecmp (tok, "copiousoutput"))
  241.       {
  242.         copiousoutput = TRUE;
  243.         if (entry)
  244.           entry->copiousoutput = TRUE;
  245.       }
  246.       else if (!strncasecmp (tok, "composetyped", 12))
  247.       {
  248.         /* this compare most occur before compose to match correctly */
  249.         /* this isn't particularly well specified in the rfc, so skip it */
  250.       }
  251.       else if (!strncasecmp (tok, "compose", 7))
  252.       {
  253.         tok += 7;
  254.         tok = mutt_skip_whitespace (tok);
  255.         if (*tok == '=')
  256.         {
  257.           composecommand = TRUE;
  258.           if (entry)
  259.           {
  260.         tok = mutt_skip_whitespace (++tok);
  261.         safe_free ((void **) &entry->composecommand);
  262.         entry->composecommand = safe_strdup (tok);
  263.           }
  264.         }
  265.         else 
  266.           mutt_error ("Improperly formated mailcap entry for type %s", type);
  267.       } 
  268.       else if (!strncasecmp (tok, "print", 5))
  269.       {
  270.         tok+=5;
  271.         tok = mutt_skip_whitespace (tok);
  272.         if (*tok == '=')
  273.         {
  274.           printcommand = TRUE;
  275.           if (entry)
  276.           {
  277.         tok = mutt_skip_whitespace (++tok);
  278.         safe_free ((void **) &entry->printcommand);
  279.         entry->printcommand = safe_strdup(tok);
  280.           }
  281.         }
  282.         else 
  283.           mutt_error("Improperly formated mailcap entry for type %s", type);
  284.       }
  285.       else if (!strncasecmp (tok, "edit", 4))
  286.       {
  287.         tok+=4;
  288.         tok = mutt_skip_whitespace (tok);
  289.         if (*tok == '=')
  290.         {
  291.           editcommand = TRUE;
  292.           if (entry)
  293.           {
  294.         tok = mutt_skip_whitespace (++tok);
  295.         safe_free((void **) &entry->editcommand);
  296.         entry->editcommand = safe_strdup(tok);
  297.           }
  298.         }
  299.         else 
  300.           mutt_error ("Improperly formated mailcap entry for type %s", type);
  301.       }
  302.       else if (